﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.RegularExpressions;


namespace CY_MVC.Utility
{
    public class HttpWebUtility
    {
        #region 接受文件类型枚举

        public enum Accept : int
        {
            All = 0,
            Html = 1,
            Css = 2,
            Js = 3,
            Image = 4,
        }

        #endregion

        #region UserAgent类型枚举

        public enum UserAgents : int
        {
            IE6 = 0,
            IE8 = 1,
            IE9 = 2,
            Firefox3_6 = 3,
            Firefox4_0 = 4,
            Firefox11_0 = 5,
            Chrome11 = 6,
            Chrome15 = 7,
            Chrome19 = 8,
            Maxthon = 9,
        }

        #endregion

        #region 请求类型枚举

        public enum Method : int
        {
            GET = 0,
            POST = 1,
            PUT = 3,
            HEAD = 4,
        }

        #endregion

        #region 变量

        public HttpWebRequest MyRequest { get; set; }
        public HttpWebResponse MyResponse { get; set; }
        public CookieContainer MyCookieContainer { get; set; }
        public MemoryStream MyMemoryStream { get; set; }

        private Stream MyStream;
        private StreamReader MyStreamReader;

        private const string PostContentType = "application/x-www-form-urlencoded; charset=UTF-8";

        private static readonly Regex RegexCharSet = new Regex("charset=(?<charset>[\\w-]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase);

        public Uri Url { get; set; }
        public Encoding RequestEncoding { get; set; }
        public Encoding ResponseEncoding { get; set; }
        public Accept AccpetType { get; set; }
        public Method RequestMethod { get; set; }
        public string UrlReferer { get; set; }
        public bool JScriptEscape { get; set; }
        public string RequestStr { get; set; }
        public int TimeOut { get; set; }
        public bool KeepAlive { get; set; }
        public UserAgents UserAgent { get; set; }

        #endregion

        public HttpWebUtility()
        {
            MyCookieContainer = new CookieContainer();

            RequestEncoding = Encoding.UTF8;
            ResponseEncoding = Encoding.UTF8;
            AccpetType = Accept.All;
            RequestMethod = Method.GET;
            UrlReferer = string.Empty;
            JScriptEscape = false;
            RequestStr = string.Empty;
            TimeOut = 10000;
            UserAgent = UserAgents.IE8;
            KeepAlive = true;
        }

        public void Request()
        {
            MyRequest = (HttpWebRequest)WebRequest.Create(Url);
            MyRequest.CookieContainer = MyCookieContainer;
            MyRequest.Headers.Add("Accept-Encoding", "gzip,deflate");
            MyRequest.Method = RequestMethod.ToString();
            MyRequest.Accept = GetAccept();
            MyRequest.UserAgent = GetUserAgent();
            MyRequest.Timeout = TimeOut;
            MyRequest.KeepAlive = KeepAlive;

            if (!string.IsNullOrEmpty(UrlReferer))
            {
                MyRequest.Referer = UrlReferer;
            }

            if (Url.Scheme == "https")
            {
                ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckValidationResult);
                MyRequest.ServicePoint.Expect100Continue = false;
            }

            if (RequestMethod == Method.POST)
            {
                MyRequest.ContentType = PostContentType;
                MyStream = MyRequest.GetRequestStream();
            }
        }

        public string Response()
        {
            string res = string.Empty;
            try
            {
                if (RequestMethod == Method.POST)
                {
                    byte[] buffer = RequestEncoding.GetBytes(RequestStr);
                    MyStream.Write(buffer, 0, buffer.Length);
                    MyStream.Flush();
                    MyStream.Close();
                }
                using (MyResponse = (HttpWebResponse)MyRequest.GetResponse())
                {
                    using (MyStream = MyResponse.GetResponseStream())
                    {
                        List<byte> buffer = new List<byte>();

                        switch (MyResponse.ContentEncoding.ToLower())
                        {
                            case "gzip":
                                using (GZipStream MyGzipStream = new GZipStream(MyStream, CompressionMode.Decompress))
                                {
                                    int bytenow = -1;
                                    do
                                    {
                                        bytenow = MyGzipStream.ReadByte();
                                        if (bytenow != -1)
                                            buffer.Add(byte.Parse(bytenow.ToString()));
                                    }
                                    while (bytenow != -1);
                                }
                                break;
                            case "deflate":
                                using (DeflateStream MyDeflateStream = new DeflateStream(MyStream, CompressionMode.Decompress))
                                {
                                    int bytenow = -1;
                                    do
                                    {
                                        bytenow = MyDeflateStream.ReadByte();
                                        if (bytenow != -1)
                                            buffer.Add(byte.Parse(bytenow.ToString()));
                                    }
                                    while (bytenow != -1);
                                }
                                break;
                            default:
                                {
                                    int bytenow = -1;
                                    do
                                    {
                                        bytenow = MyStream.ReadByte();
                                        if (bytenow != -1)
                                            buffer.Add(byte.Parse(bytenow.ToString()));
                                    }
                                    while (bytenow != -1);
                                }
                                break;
                        }

                        MyMemoryStream = new MemoryStream(buffer.ToArray());

                        using (MyStreamReader = new StreamReader(MyMemoryStream, ResponseEncoding))
                        {
                            res = MyStreamReader.ReadToEnd();
                            Match match = RegexCharSet.Match(res);
                            if (match.Success && !string.IsNullOrEmpty(match.Groups["charset"].Value))
                            {
                                Encoding tempencoding = Encoding.GetEncoding(match.Groups["charset"].Value);
                                if (ResponseEncoding.WebName != tempencoding.WebName)
                                {
                                    ResponseEncoding = tempencoding;
                                    MyMemoryStream.Seek(0, SeekOrigin.Begin);
                                    MyStreamReader = new StreamReader(MyMemoryStream, ResponseEncoding);
                                    res = MyStreamReader.ReadToEnd();
                                }
                            }
                            MyStreamReader.Close();
                        }
                    }
                    MyResponse.Close();
                }
            }
            catch
            { }
            finally
            {
                MyRequest.Abort();
            }
            if (JScriptEscape)
            {
                res = Microsoft.JScript.GlobalObject.unescape(res);
            }
            return res;
        }


        #region Cookies操作

        public string GetCookie(string p_Name)
        {
            string res = string.Empty;
            foreach (Cookie item in MyCookieContainer.GetCookies(Url))
            {
                if (item.Name == p_Name)
                {
                    res = item.Value;
                }
            }
            return res;
        }

        public void SetCookie(string p_Name, string p_Value)
        {
            bool res = false;
            foreach (Cookie item in MyCookieContainer.GetCookies(Url))
            {
                if (item.Name == p_Name)
                {
                    item.Value = p_Value;
                    res = true;
                }
            }
            if (!res)
            {
                Cookie item = new Cookie(p_Name, p_Value);
                item.Expires = DateTime.Now.AddDays(1);
                MyCookieContainer.Add(item);
            }
        }

        public string GetCookieHeader(string key)
        {
            return MyCookieContainer.GetCookieHeader(Url);
        }

        #endregion

        #region 设置HttpWebRequest

        private string GetUserAgent()
        {
            string res = string.Empty;
            switch (UserAgent)
            {
                case UserAgents.IE6:
                    res = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)";
                    break;
                case UserAgents.IE8:
                    res = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727;)";
                    break;
                case UserAgents.IE9:
                    res = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; .NET4.0E; BOIE9;ZHCN)"; ;
                    break;
                case UserAgents.Firefox3_6:
                    res = "Mozilla/5.0 (Windows NT 5.1; rv:1.9.2) Gecko/20100101 Firefox/3.6";
                    break;
                case UserAgents.Firefox4_0:
                    res = "Mozilla/5.0 (Windows NT 5.1; rv:2.0) Gecko/20110101 Firefox/4.0";
                    break;
                case UserAgents.Firefox11_0:
                    res = "Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko/20100101 Firefox/11.0";
                    break;
                case UserAgents.Chrome11:
                    res = "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.21 (KHTML, like Gecko) Chrome/11.0.682.0 Safari/534.21";
                    break;
                case UserAgents.Chrome15:
                    res = "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.21 (KHTML, like Gecko) Chrome/15.0.849.0 Safari/534.21";
                    break;
                case UserAgents.Chrome19:
                    res = "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.21 (KHTML, like Gecko) Chrome/19.0.1041.0 Safari/535.21";
                    break;
                case UserAgents.Maxthon:
                    res = "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/533.1 (KHTML, like Gecko) Maxthon/3.0.8.2 Safari/533.1";
                    break;
                default:
                    res = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727;)";
                    break;
            }
            return res;
        }

        private string GetAccept()
        {
            string res = string.Empty;
            switch (AccpetType)
            {
                case Accept.All:
                    res = "*/*";
                    break;
                case Accept.Html:
                    res = "text/html, application/xhtml+xml";
                    break;
                case Accept.Css:
                    res = "text/css";
                    break;
                case Accept.Js:
                    res = "application/x-javascript";
                    break;
                case Accept.Image:
                    res = "image/*";
                    break;
                default:
                    res = "*/*";
                    break;
            }
            return res;
        }

        private bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            //直接确认，否则打不开
            return true;
        }

        public void RandomUserAgent()
        {
            Random random = new Random();
            int index = random.Next(10);
            UserAgent = (UserAgents)index;
        }

        #endregion

        //#region Socket接收数据

        //private string SourceSocket(string p_Url, Encoding p_Encoding, string p_BackUrl, string p_CookieName, string p_Postparam)
        //{
        //    Uri uri = new Uri(p_BackUrl);

        //    string res = string.Empty;
        //    try
        //    {
        //        if (MyRequest == null && MyResponse == null)
        //        {
        //            MyRequest = (HttpWebRequest)WebRequest.Create(p_Url);

        //            CookieContainer cc = new CookieContainer();
        //            MyRequest.KeepAlive = true;
        //            MyRequest.Timeout = 120000;
        //            MyRequest.CookieContainer = cc;
        //            MyRequest.Headers.Add("Accept-Encoding", "gzip, deflate");
        //            MyResponse = (HttpWebResponse)MyRequest.GetResponse();
        //            MyResponse.GetResponseStream();
        //            MyResponse.Close();
        //            MyRequest.Abort();
        //        }
        //        else
        //        {
        //            Thread.Sleep(1000);
        //        }
        //        IPAddress hostIp = Dns.GetHostEntry(uri.Host).AddressList[0];
        //        IPEndPoint ep = new IPEndPoint(hostIp, 80);
        //        Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        //        try
        //        {
        //            client.Connect(ep);
        //        }
        //        catch (SocketException e)
        //        {
        //            Console.WriteLine(e.Message);
        //        }

        //        if (!string.IsNullOrEmpty(p_Postparam))
        //        {
        //            client.Send(p_Encoding.GetBytes("POST " + uri.AbsoluteUri + " HTTP/1.1\r\n"));
        //        }
        //        else
        //        {
        //            client.Send(p_Encoding.GetBytes("GET " + uri.AbsoluteUri + " HTTP/1.1\r\n"));
        //        }
        //        client.Send(p_Encoding.GetBytes("Host:" + uri.Host + "\r\n"));
        //        client.Send(p_Encoding.GetBytes("User-Agent:Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 ( .NET CLR 3.5.30729; .NET4.0E)\r\n"));
        //        client.Send(p_Encoding.GetBytes("Accept:text/javascript, text/html, application/xml, text/xml, */*\r\n"));
        //        client.Send(p_Encoding.GetBytes("Accept-Language:zh-cn,zh;q=0.5\r\n"));
        //        client.Send(p_Encoding.GetBytes("Accept-Encoding:gzip,deflate\r\n"));
        //        client.Send(p_Encoding.GetBytes("Accept-Charset:GB2312,utf-8;\r\n"));
        //        client.Send(p_Encoding.GetBytes("Content-Type: text/xml;charset=utf-8\r\n"));
        //        client.Send(p_Encoding.GetBytes("Keep-Alive:115\r\n"));
        //        client.Send(p_Encoding.GetBytes("SOAPAction: want\r\n"));
        //        client.Send(p_Encoding.GetBytes("Ajax-method: GameListChanged\r\n"));
        //        client.Send(p_Encoding.GetBytes("Content-Length: " + p_Postparam.Length.ToString() + "\r\n"));
        //        client.Send(p_Encoding.GetBytes("Connection:keep-alive\r\n"));
        //        client.Send(p_Encoding.GetBytes("X-Requested-With:XMLHttpRequest\r\n"));
        //        client.Send(p_Encoding.GetBytes("X-Prototype-Version:1.6.0.2\r\n"));
        //        client.Send(p_Encoding.GetBytes("Referer:" + p_Url + "\r\n"));
        //        client.Send(p_Encoding.GetBytes("Cookie:" + p_CookieName + "=" + MyResponse.Cookies[p_CookieName].Value + "\r\n"));
        //        client.Send(p_Encoding.GetBytes("\r\n"));
        //        if (!string.IsNullOrEmpty(p_Postparam))
        //        {
        //            client.Send(p_Encoding.GetBytes(p_Postparam + "\r\n"));
        //        }

        //        using (MyStream = new MemoryStream(ReceiveData(client)))
        //        {
        //            switch (MyResponse.ContentEncoding.ToLower())
        //            {
        //                case "gzip":
        //                    using (GZipStream gzipStream = new GZipStream(MyStream, CompressionMode.Decompress))
        //                    {
        //                        using (MyStreamReader = new StreamReader(gzipStream, p_Encoding))
        //                        {
        //                            res = MyStreamReader.ReadToEnd();
        //                            MyStreamReader.Close();
        //                        }
        //                    }
        //                    break;
        //                case "deflate":
        //                    using (DeflateStream deflateStream = new DeflateStream(MyStream, CompressionMode.Decompress))
        //                    {
        //                        using (MyStreamReader = new StreamReader(deflateStream, p_Encoding))
        //                        {
        //                            res = MyStreamReader.ReadToEnd();
        //                            MyStreamReader.Close();
        //                        }
        //                    }
        //                    break;
        //                default:
        //                    using (MyStreamReader = new StreamReader(MyStream, p_Encoding))
        //                    {
        //                        res = MyStreamReader.ReadToEnd();
        //                        MyStreamReader.Close();
        //                    }
        //                    break;
        //            }
        //        }
        //    }
        //    catch
        //    { }
        //    finally
        //    { }
        //    return res;
        //}

        ///// <summary>
        ///// 接收数据的方法
        ///// </summary>
        ///// <param name="socket">Socket连接</param>
        ///// <param name="size">要接收的数据长度</param>
        ///// <returns>返回收到的字节数组</returns>
        //private byte[] ReceiveData(Socket socket, int size)
        //{
        //    int total = 0;     //收到的总的字节数
        //    int dataleft = size;    //剩余的字节数
        //    byte[] data = new byte[size];  //接收数据的数组
        //    int rece = 0;      //收到的字节数
        //    if (dataleft != 0)
        //    {
        //        //循环接收数据
        //        while (total < size)
        //        {
        //            rece = socket.Receive(data, total, dataleft, SocketFlags.None);
        //            //如果收到的字节数为0，那么说明连接断开，返回空的字节数组
        //            if (rece == 0)
        //            {
        //                break;
        //            }
        //            total += rece;     //收到的字节数长度++
        //            dataleft -= rece;     //剩余的字节数--
        //        }
        //    }
        //    else
        //    {
        //        Queue<byte> list = new Queue<byte>();
        //        byte[] buff = new byte[1024];
        //        while (true)
        //        {
        //            rece = socket.Receive(buff, buff.Length, SocketFlags.None);
        //            //如果收到的字节数为0，那么说明连接断开，返回空的字节数组
        //            if (rece == 0)
        //            {
        //                data = list.ToArray();
        //                break;
        //            }
        //            foreach (var item in buff)
        //            {
        //                list.Enqueue(item);
        //            }
        //        }
        //    }
        //    return data;      //返回
        //}

        //private byte[] ReceiveData(Socket socket)
        //{
        //    StringBuilder header = new StringBuilder();
        //    string headertext = string.Empty;
        //    int bodylength = 0;
        //    while (true)
        //    {
        //        byte[] data = new byte[1];
        //        //接收一个字节
        //        int rece = socket.Receive(data, 1, SocketFlags.None);

        //        //转换为char
        //        char c = (char)data[0];

        //        header.Append(c);
        //        //检查是否到了包头末尾，如果到了包头末尾，那么停止
        //        //读取
        //        if (header.ToString().IndexOf("\r\n\r\n") > 0)
        //        {
        //            string content = "CONTENT-LENGTH:";
        //            int start = header.ToString().ToUpper().IndexOf(content);
        //            headertext = header.ToString().Substring(start + content.Length);
        //            int end = headertext.IndexOf("\r\n");
        //            headertext = headertext.Substring(0, end); //包体长度
        //            break;
        //        }
        //    }
        //    int.TryParse(headertext, out bodylength);
        //    return ReceiveData(socket, bodylength);
        //}

        //#endregion
    }
}
